import 'dart:async';
import 'dart:convert';

import 'package:shared_preferences/shared_preferences.dart';
import 'package:sweet_app/bloc/bloc_provider.dart';
import 'package:rxdart/rxdart.dart';
import 'package:sweet_app/bloc/search_bloc.dart';
import 'package:sweet_app/db/db_helper.dart';
import 'package:sweet_app/model/add_friend_history.dart';
import 'package:sweet_app/model/message_model.dart';
import 'package:sweet_app/model/user.dart';
import 'package:sweet_app/socket_io.dart';

class AppEvent {
  static const login = 0;
  static const register = 1;
  static const home = 2;
}

const socket_host = "192.168.1.107";
const socket_port = 9090;

class ApplicationBloc implements BaseBloc {
  final _appEvent = BehaviorSubject<int>();

  Sink<int> get _appEventSink => _appEvent.sink;

  Stream<int> get appEventStream => _appEvent.stream;

  final _notifyStreamController = BehaviorSubject<NotifyMessage>();

  Sink<NotifyMessage> get _notifySink => _notifyStreamController.sink;

  Stream<NotifyMessage> get notifyMessageStream =>
      _notifyStreamController.stream;

  final List<AddHistory> _addHistoryList = [];

  final _addHistoryStreamController = BehaviorSubject<List<AddHistory>>();

  Sink<List<AddHistory>> get _addHistorySink => _addHistoryStreamController.sink;

  Stream<List<AddHistory>> get addHistoryStream => _addHistoryStreamController.stream;

  final _searchSubject = StreamController<SearchBody>.broadcast();

  Sink<SearchBody> get _searchSink => _searchSubject.sink;

  Stream<SearchBody> get searchStream => _searchSubject.stream;

  SocketIOManager _socketIOManager;

  final DatabaseHelper _databaseHelper = DatabaseHelper();

  Timer _timer;

  Timer _heartbeatTimer;

  ApplicationBloc() {
    Future.delayed(Duration(seconds: 1), () {
      isLogin();
    });

    _timer = Timer.periodic(Duration(seconds: 15), (t) {
      //模拟通知
//      _notifySink.add(NotifyMessage(title: "这是通知",
//          content: DateTime.now().toLocal().toString()));
    });

    Future.delayed(Duration(seconds: 20), () async {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      _heartbeatTimer = Timer.periodic(Duration(seconds: 30), (t) {
        if (prefs.getString("token") != null)
          _socketIOManager.write(
              """{"token": "${prefs.getString("token")}", "type" : "${MessageType.ping}"}""");
      });
    });
  }

  void add(SearchBody body) {
    _searchSink.add(body);
  }

  void addEvent(int event) {
    _appEventSink.add(event);
  }

  Future<void> isLogin() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String token = prefs.getString("token");
    print('isLogin token: $token');
    Future.delayed(Duration(seconds: 1), () {
      if (token != null) {
        _appEventSink.add(AppEvent.home);
        _socketIOManager = SocketIOManager(
            socket_host, socket_port, _messageCall,
            delimit: "\n");
        // 建立socket连接
      } else {
        _socketIOManager?.close();
        _appEventSink.add(AppEvent.login);
      }
    });
  }

  Future<MessageModel> sendMessage(MessageModel m) async {
    try {
      await _socketIOManager.write(m.toJson());
      return m;
    } catch (e) {
      print("sendMessage: ${e}");
      return Future.error("消息失败");
    }
  }

  Future<void> logout() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.remove("token");
    _socketIOManager?.close();
    addEvent(AppEvent.login);
  }

  void _messageCall(String message) {
    final model = MessageModel.fromJson(json.decode(message));
    // todo 判断什么消息 然后set flag
    switch (model.type) {
      case MessageType.text:
        return;
      case MessageType.add:
        _addHistoryList.add(AddHistory.fromMessage(model));
        print('_history list: ${_addHistoryList}');
        _addHistorySink.add(List.unmodifiable(_addHistoryList));
        return;
      case MessageType.ping:
    }
  }

  Future<int> insertDb(String sql, [List arguments]) async {
    int i = await _databaseHelper.insert(sql, arguments);
    return i;
  }

  Future<int> updateDb(String sql, [List arguments]) async {
    int i = await _databaseHelper.update(sql, arguments);
    return i;
  }

  Future<int> deleteDb(String sql, [List arguments]) async {
    int i = await _databaseHelper.delete(sql, arguments);
    return i;
  }

  Future<List<Map<String, dynamic>>> queryDb(String sql,
      [List arguments]) async {
    var data = await _databaseHelper.query(sql, arguments);
    return data;
  }

  @override
  void dispose() {
    if (_socketIOManager != null) _socketIOManager.close();

    if (_databaseHelper != null) _databaseHelper.close();

    if (_timer != null) _timer.cancel();

    if (_appEvent != null) _appEvent.close();

    if (_heartbeatTimer != null) _heartbeatTimer.cancel();

    if (_databaseHelper != null) _databaseHelper.close();

    if (_notifyStreamController != null) _notifyStreamController.close();

    if (_searchSubject != null) _searchSubject.close();

    if (_addHistoryStreamController != null)
      _addHistoryStreamController.close();
  }

  void removeNotify() {
    _notifySink.add(null);
  }

  Future<void> saveUserInfo(User user, String token) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setString("id", user.id);
    prefs.setString("name", user.name);
    prefs.setString("phone", user.phone);
    prefs.setString("password", user.password);
    prefs.setString("token", token);
    _socketIOManager =
        SocketIOManager(socket_host, socket_port, _messageCall, delimit: "\n");
  }

}

class NotifyMessage {
  final String title;
  final String content;

  NotifyMessage({this.title, this.content});

  @override
  String toString() {
    return 'NotifyMessage{title: $title, content: $content}';
  }
}
